﻿using ServerListerner.Connections;
using ServerListerner.Helper;

using System;
using System.Linq.Expressions;
using System.Net;
using System.Net.Sockets;
using System.Reflection;

namespace ServerListerner {
    public class UDPServer:IDisposable {
        private readonly Socket _socket;
        private IPAddress address;
        private readonly int _port;
        private Action<IUDPConnection> _action;
        private UDPConnection _connection;
        public UDPServer(int port) {
            this._port = port;
             _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        }
        public UDPServer(IPAddress? ip, int port):this(port) {
            this.address = ip ?? IPAddress.Any;
        }
        public UDPServer(string? ip, int port) : this(IPAddress.Parse(ip??"0.0.0.0"), port) { }

        public bool StartListen(Action<IUDPConnection> action) {
            try
            {
                if (_port.PortInUse(false))
                    return false;
                this._action = action;
                this.address = this.address ?? IPAddress.Any;
                _socket.Bind(new IPEndPoint(address, _port));
                StartAccept();
                return _port.PortInUse(false);
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        public bool StopListen() {
            _connection.Dispose();
            this.CloseSocket();
            return !_port.PortInUse(false);
        }
        private void StartAccept() {
            _connection = new UDPConnection(this._socket, this._action);
        }
        public void Dispose()
        {
            this.CloseSocket();
            _action = null;
        }
        private void CloseSocket()
        {
            this._socket.Shutdown(SocketShutdown.Both);
            this._socket.Close();
            this._socket.Dispose();
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }
    }
}